package com.sky.service.admin.impl;

import com.sky.dto.GoodsSalesDTO;
import com.sky.mapper.admin.ReportMapper;

import com.sky.service.admin.ReportService;
import com.sky.vo.OrderDayAmountVo;
import com.sky.vo.OrderReportVO;
import com.sky.vo.SalesTop10ReportVO;
import com.sky.vo.TurnoverReportVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;


@Service
@Slf4j
public class ReportServiceImlpl implements ReportService {
    @Autowired
    private ReportMapper reportMapper;

    //获取从开始到结束的 每一天的时间
    private List<LocalDate> getAllDays(LocalDate begin, LocalDate end) {
        ArrayList<LocalDate> allDays = new ArrayList<>();
        allDays.add(begin);//添加开始时间
        //计算第二天（只要开始时间不是结束时间）
        while (!begin.equals(end)) {
            //开始时间就在基础的时间上+1
            begin = begin.plusDays(1);
            allDays.add(begin);
        }
        return allDays;
    }

    /**
     * 根据时间区间统计营业额
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public TurnoverReportVO yingYeE(LocalDate begin, LocalDate end) {
        log.info("根据时间区间统计营业额，选择开始时间{}", begin);
        log.info("根据时间区间统计营业额，选择结束时间{}", end);
        //从开始到结束的每一天（调用方法，获取到从开始到结束的每一天时间）
        List<LocalDate> allDays = getAllDays(begin, end);


        //每日金额（最后获取的金额遍历挨着塞进去）
        ArrayList<BigDecimal> amountList = new ArrayList<>();

        LocalDate endAdd1 = end.plusDays(1);

        //按天查询金额                    开始      结束的+1一天
        List<OrderDayAmountVo> orderDayAmountVos = reportMapper.yingYeE(begin, endAdd1);
        //封装        每天       的订单金额数据
        for (LocalDate oneDay : allDays) {           //               ?       每天的时间     对比时间相同的一天
            OrderDayAmountVo fist = orderDayAmountVos.stream().filter(o -> o.getOrderTime().equals(oneDay)).findFirst().orElse(null);
            if (fist == null) {
                //如果有一天为空 营业额设置为0
                amountList.add(new BigDecimal(0));
            } else {
                //否则就拿到当天的营业额 塞进去
                amountList.add(fist.getAmount());
            }
        }


        //封装TurnoverReportVO对象返回
        TurnoverReportVO reportVO = TurnoverReportVO.builder()
                //日期                                            从开始到结束的每一天 集合
                .turnoverList(StringUtils.collectionToCommaDelimitedString(allDays))
                //营业额                                            每天的营业额集合 放进去
                .dateList(StringUtils.collectionToCommaDelimitedString(amountList)).build();

        log.info("封装TurnoverReportVO对象返回{}", reportVO);

        return reportVO;
    }


    /**
     * 用户统计
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public OrderReportVO orderStatistics(LocalDate begin, LocalDate end) {
        log.info("用户统计，选择开始时间{}", begin);
        log.info("用户统计，选择结束时间{}", end);
        //获取每天
        List<LocalDate> allDays = getAllDays(begin, end);
        //每日订单       每日有效订单
        ArrayList<Integer> totalist = new ArrayList<>();
        ArrayList<Integer> completeList = new ArrayList<>();
        //获取 OrderDayAmountVo对象的集合（订单的时间，总金额，总订单，有效订单）
        List<OrderDayAmountVo> orderDayAmountVos = reportMapper.orderStatistics(begin, end.plusDays(1));

        for (LocalDate oneDay : allDays) {    // 对流中的元素
            OrderDayAmountVo orderDayAmountVo = orderDayAmountVos
                    // 查找某一天的订单数据    进行过滤，只保留那些其getOrderTime()方法 返回值与oneDay相等的元素
                    .stream().filter(o -> o.getOrderTime().equals(oneDay))
                    //过滤后的流中获取第一个元素（如果没有的话）
                    .findFirst().orElse(null);

            if (orderDayAmountVo == null) {
                //日期 设置为0
                totalist.add(0);
                //有效订单设置为0
                completeList.add(0);
            } else {
                // 否则添加实际的订单数据 获取的数据 设置进去
                totalist.add(orderDayAmountVo.getTotaNum());
                totalist.add(orderDayAmountVo.getCompleteNum());
            }
        }
        //订单总数量         每日订单                   避免 null   相加
        Integer totaNum = totalist.stream().reduce(0,Integer::sum);
        //有效订单数量        每日有效订单         相加
        Integer comple = completeList.stream().reduce(0,Integer::sum);

        log.info("订单总数量{}", totaNum);
        log.info("有效订单数量{}", comple);

        //定义完成率默认值 避免空指针异常
        double rete = 0d;
        if (totaNum != 0) {
            //整数相除 (double)
            rete = (double) comple / totaNum;
        }


        //封装返回
        OrderReportVO orderReportVO = OrderReportVO.builder().
                //日期      字符串工具类       ，分割的方法           每一天
                        dateList(StringUtils.collectionToCommaDelimitedString(allDays))
                //每日有效订单数
                .validOrderCountList(StringUtils.collectionToCommaDelimitedString(completeList))
                //每日订单完成率
                .orderCountList(StringUtils.collectionToCommaDelimitedString(totalist))
                //订单总数
                .validOrderCount(totaNum)
                //有效订单
                .validOrderCount(comple)
                //完成率
                .orderCompletionRate(rete).build();

        log.info("封装orderReportVO对象返回{}", orderReportVO);
        return orderReportVO;
    }


    /**
     * 销量前十排行
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public SalesTop10ReportVO top10(LocalDate begin, LocalDate end) {
        log.info("选择销量前10，选择开始时间{}", begin);
        log.info("选择销量前10，选择结束时间{}", end);

        //获取菜品名称和销量
        List<GoodsSalesDTO> salesDTOList = reportMapper.top10(begin, end.plusDays(1));
        //获取菜品集合                                                转成集合
        List<String> nameList = salesDTOList.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList());
        //获取数量集合
        List<Integer> NumLise = salesDTOList.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList());

        log.info("获取菜品集合{}", nameList);
        log.info("获取数量集合{}", NumLise);

        //封装数据返回                           工具类转字符串  以,分隔
        SalesTop10ReportVO vo = SalesTop10ReportVO.builder()
                .nameList(StringUtils.collectionToCommaDelimitedString(nameList))
                .numberList(StringUtils.collectionToCommaDelimitedString(NumLise)).build();

        log.info("封装SalesTop10ReportVO对象返回{}", vo);
        return vo;

    }


}
